<?php

/**
 * gd_model.php
 *
 * @copyright  2017 opencart.cn - All Rights Reserved
 * @link       http://www.guangdawangluo.com
 * @author     Edward Yang <yangjin@opencart.cn>
 * @created    2/23/17 10:19
 * @modified   2/23/17 10:19
 */
class GdModel extends Model
{
    protected $table;
    public $primaryName = 'id';
    private $allFields = array();
    private $allFieldsName = array();
    private $fields = array();

    public function __construct($registry)
    {
        parent::__construct($registry);
        $this->allFields = $this->getAllFields();
        $this->allFieldsName = array_keys($this->getAllFields());
        $this->primaryName = $this->getPrimaryName();
        $this->fields = $this->getFields();
    }

    /**
     * @return string
     */
    public function getTable()
    {
        return $this->table;
    }

    /**
     * @return string
     * @throws Exception
     */
    public function getPrimaryName()
    {
        $name = $this->table . '_' . $this->primaryName;
        if (in_array($this->primaryName, $this->allFieldsName)) {
            return $this->primaryName;
        } elseif (in_array($name, $this->allFieldsName)) {
            return $name;
        }
        throw new \Exception('Invalid primary name');
    }

    /**
     * @return array
     * @throws Exception
     */
    public function getAllFields()
    {
        if ($this->allFields) {
            return $this->allFields;
        }
        $sql = "select column_name, data_type from information_schema.columns";
        $sql .= " where table_name = '" . DB_PREFIX . $this->table . "'";
        $sql .= " and table_schema = '" . DB_DATABASE . "'";
        $query = $this->db->query($sql);
        $fields = array();
        if (!$rows = $query->rows) {
            throw new \Exception('Invalid table and there is no fields!');
        }
        foreach ($rows as $row) {
            $fields[$row['column_name']] = $row['data_type'];
        }
        return $fields;
    }

    /**
     * @return array
     */
    public function getFields()
    {
        if ($this->fields) {
            return $this->fields;
        }
        foreach ($this->allFields as $field => $type) {
            if ($field != $this->primaryName) {
                $this->fields[$field] = $type;
            }
        }
        return $this->fields;
    }

    /**
     * @param $id
     * @return mixed
     */
    public function find($id)
    {
        $sql = "SELECT DISTINCT * FROM " . DB_PREFIX . $this->table . " WHERE " . $this->primaryName . " = '" . (int)$id . "'";
        $query = $this->db->query($sql);
        return $query->row;
    }

    /**
     * @param $data
     * @return bool
     */
    public function create($data)
    {
        $allFields = $this->getFields();
        foreach ($allFields as $field => $type) {
            if ($field == $this->primaryName) {
                continue;
            }
            $fields[] = "`{$field}`";
            if (isset($data[$field])) {
                $values[] = "'{$data[$field]}'";
            } elseif (in_array($field, ['date_added', 'date_modified'])) {
                $datetime = date('Y-m-d H:i:s');
                $values[] = "'{$datetime}'";
            } else {
                $values[] = "''";
            }
        }
        if (empty($fields) || empty($values)) {
            return false;
        }
        $sql = "INSERT INTO " . DB_PREFIX . $this->table . " (" . implode(',', $fields) . ") VALUES(" . implode(',', $values) . ")";
        $this->db->query($sql);
        return $this->db->getLastId();
    }

    /**
     * @param $id
     * @param $data
     */
    public function update($id, $data)
    {
        $fields = array_keys($this->getFields());
        $fieldsStrArray = array();
        foreach ($data as $field => $value) {
            if (!in_array($field, $fields) || $field == $this->primaryName) {
                continue;
            }
            $fieldsStrArray[] = "{$field} = '{$this->db->escape($value)}'";
        }
        foreach ($fields as $field => $value) {
            if (in_array($value, ['date_modified'])) {
                $datetime = date('Y-m-d H:i:s');
                $fieldsStrArray[] = "{$value} = '{$datetime}'";
            }
        }
        $fieldsSql = implode(',', $fieldsStrArray);
        $sql = "UPDATE " . DB_PREFIX . $this->table . " SET " . $fieldsSql . " WHERE " . $this->primaryName . " = '" . (int)$id . "'";
        $this->db->query($sql);
    }

    /**
     * @param $id
     */
    public function delete($id)
    {
        $sql = "DELETE FROM " . DB_PREFIX . $this->table . " WHERE " . $this->primaryName . " = '" . (int)$id . "'";
        $this->db->query($sql);
    }

    /**
     * @param $filter
     * @return mixed
     */
    public function where($filter)
    {
        $condition = array();
        if (is_array($filter)) {
            $condition = array('where' => $filter);
        }
        return $this->all($condition);
    }

    /**
     * @param array $data
     * @return mixed
     */
    public function all($data = array())
    {
        if (empty($data)) {
            $sql = "SELECT * FROM " . DB_PREFIX . $this->table . " ORDER BY " . $this->primaryName . " DESC";
            $query = $this->db->query($sql);
            return $query->rows;
        }

        $sql = "SELECT * FROM " . DB_PREFIX . $this->table;
        if (isset($data['where']) && is_array($data['where'])) {
            $sql .= " WHERE 1=1 ";
            foreach ($data['where'] as $filter => $value) {
                $sql .= " AND {$filter} = {$value}";
            }
        }

        if (isset($data['sort'])) {
            $sql .= " ORDER BY " . $data['sort'];
        } else {
            $sql .= " ORDER BY id";
        }

        if (isset($data['order']) && ($data['order'] == 'DESC')) {
            $sql .= " DESC";
        } else {
            $sql .= " ASC";
        }

        if (isset($data['start']) || isset($data['limit'])) {
            if ($data['start'] < 0) {
                $data['start'] = 0;
            }
            if ($data['limit'] < 1) {
                $data['limit'] = 20;
            }
            $sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit'];
        }
        $query = $this->db->query($sql);
        return $query->rows;
    }
}